/*
 * File: ttds_core.h
 * Author: Liang YaoZhan <262666882@qq.com>
 * Brief:  timer
 *
 * Copyright (c) 2022 - 2023 Liang YaoZhan <262666882@qq.com>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * History:
 * ================================================================
 * 2023-08-05 Liang YaoZhan <262666882@qq.com> created
 *
 */

#ifndef MYPTM_CORE_H
#define MYPTM_CORE_H

#include <stdint.h>

#include "ttds/ttds_config.h"
#include "ttds/ttds_queue.h"
#include "ttds/ttds_timer.h"

#define incompatible_pointor_type_check(ptr, t) \
    extern int incompatible_pointor_type_check_array[(sizeof(*(ptr)) == sizeof(t)) ? 1 : -1];

#define MYPTM_CPLUSPLUS_BEGIN \
    extern "C"                \
    {
#define MYPTM_CPLUSPLUS_END }

#ifdef __cplusplus
MYPTM_CPLUSPLUS_BEGIN
#endif

/************************************************** ttds_thread_t ***************************************/
/************************************************** ttds_thread_t ***************************************/

#define ttds_WAITING 0
#define ttds_YIELDED 1
#define ttds_EXITED 2
#define ttds_PAUSE 3
#define ttds_ENDED 4

typedef enum 
{
    ttds_STATE_INIT, /* */
    ttds_STATE_READY,
    ttds_STATE_PENDING,
    ttds_STATE_DEAD,
} ttds_state_t;
typedef enum 
{
    ttds_EOK,
    ttds_EEMPTY,
    ttds_ETERMINATED,
    ttds_ETIMEOUT,
} ttds_err_t;

struct _ttds_loop;
typedef struct _ttds_loop ttds_loop_t;
typedef struct _mypt_thread
{
    int lc;
    int (*entry)(struct _mypt_thread *);
    ttds_queue_t node_state;
    ttds_queue_t node_pending_resource;
    ttds_timer_t timer;
    struct _ttds_loop *p_owner;
    uint32_t ref;
    ttds_err_t err;
    ttds_state_t state;
} ttds_thread_t;
#define ttds_OBJECT(obj) ttds_thread_t obj

struct _ttds_loop
{
    ttds_thread_t *p_thread_current;
    ttds_queue_t head_state_pending;
    ttds_queue_t head_state_running;
    ttds_queue_t clip;
    ttds_tick_t ticker;
    int32_t systick;
};

struct _mypt_sem
{
    int count;
    ttds_queue_t head_pendings;
};
typedef struct _mypt_sem ttds_sem_t;

#define _DBJ_CONCATENATE_(a, b) a##b
#define _DBJ_CONCATENATE(a, b) _DBJ_CONCATENATE_(a, b)
#define CONSTEXPR_LINE _DBJ_CONCATENATE(__LINE__, U)

#define ttds_LC_SET(s)  \
    s = CONSTEXPR_LINE; \
    case CONSTEXPR_LINE:

#define LC_END(s)   \
    ttds_LC_SET(s); \
    }

#define ttds_DEF_THIS(ptr, type, obj) type *p_this = ttds_container_of((ptr), type, obj)
#define ttds_BEGIN(obj)                         \
    {                                           \
        ttds_thread_t *__p_super_this = &(obj); \
        char ttds_YIELD_FLAG = 1;               \
        switch ((__p_super_this)->lc)           \
        {                                       \
        case 0:

#define ttds_END()                         \
    __crt_label_end:                       \
    case -1:                               \
    LC_END((__p_super_this)->lc);          \
    ttds_YIELD_FLAG = 0;                   \
    (__p_super_this)->lc = CONSTEXPR_LINE; \
    if ((int)CONSTEXPR_LINE < 0)           \
        goto __crt_label_end;              \
    return ttds_ENDED;                     \
    }

#define ttds_WAIT_UNTIL(condition)         \
    do                                     \
    {                                      \
        ttds_LC_SET((__p_super_this)->lc); \
        if (!(condition))                  \
        {                                  \
            return ttds_WAITING;           \
        }                                  \
    } while (0)

#define ttds_WAIT_WHILE(cond) ttds_WAIT_UNTIL(!(cond))

#define ttds_RESTART()            \
    do                            \
    {                             \
        (__p_super_this)->lc = 0; \
        return ttds_WAITING;      \
    } while (0)

#define ttds_EXIT() goto __crt_label_end;

#define ttds_YIELD()                       \
    do                                     \
    {                                      \
        ttds_YIELD_FLAG = 0;               \
        ttds_LC_SET((__p_super_this)->lc); \
        if (ttds_YIELD_FLAG == 0)          \
        {                                  \
            return ttds_YIELDED;           \
        }                                  \
    } while (0)

#define ttds_sem(sem) ttds_sem_t sem

#define ttds_error_code() (__p_super_this->err)

#define ttds_sem_take(p_sem, timeout)                                                                            \
    do                                                                                                           \
    {                                                                                                            \
        ttds_YIELD_FLAG = 0;                                                                                     \
        ttds_LC_SET((__p_super_this)->lc);                                                                       \
        if (ttds_YIELD_FLAG == 0)                                                                                \
        {                                                                                                        \
            ttds_sem_t *__ptr = (p_sem);                                                                         \
            extern int incompatible_pointor_type_check_array[(sizeof(*(p_sem)) == sizeof(ttds_sem_t)) ? 1 : -1]; \
            ttds_err_t _local_err_pt = ttds_sem_prepare_take(__ptr, timeout, __p_super_this);                    \
            if (_local_err_pt == ttds_EEMPTY)                                                                    \
            {                                                                                                    \
                return ttds_YIELDED;                                                                             \
            }                                                                                                    \
        }                                                                                                        \
    } while (0)
#define ttds_sem_reset(p_sem)                                                                                \
    do                                                                                                       \
    {                                                                                                        \
        extern int incompatible_pointor_type_check_array[(sizeof(*(p_sem)) == sizeof(ttds_sem_t)) ? 1 : -1]; \
        ttds_sem_t *__ptr = (p_sem);                                                                         \
        __ptr->count = 0;                                                                                    \
    } while (0)

#define ttds_DO                          \
    do                                   \
    {                                    \
        ttds_LC_SET(__p_super_this->lc); \
    } while (0);

#define ttds_CONTINUE return ttds_WAITING
#define ttds_WHILE(cond)         \
    do                           \
    {                            \
        if (cond)                \
            return ttds_WAITING; \
    } while (0)

#define ttds_thread_delay(tick)                          \
    do                                                   \
    {                                                    \
        ttds_thread_prepare_delay(__p_super_this, tick); \
        ttds_YIELD();                                    \
    } while (0)

/* you should define this function before using ttds_DELAY */
int32_t ttds_thread_sys_tick_get_ms(void);

void ttds_sem_init(ttds_sem_t *p_this, int init_count);
ttds_err_t ttds_sem_prepare_take(ttds_sem_t *p_this, int delay_tick, ttds_thread_t *p_thread); /* delay_tick: 0 forevery */
void ttds_sem_give(ttds_sem_t *p_this, int count);
void ttds_sem_give_all(ttds_sem_t *p_this);
void ttds_sem_destroy(ttds_sem_t *p_this);

void ttds_thread_init(ttds_thread_t *p_thread, int (*entry)(ttds_thread_t *));
void ttds_thread_startup(ttds_thread_t *p_thread);
void ttds_thread_prepare_delay(ttds_thread_t *p_this, int tick);
void ttds_thread_stop(ttds_thread_t *p_thread);
void ttds_thread_resume(ttds_thread_t *p_thread, int code);
void ttds_thread_join(ttds_thread_t *p_thread);

void ttds_loop_init(ttds_loop_t *p_this);
void ttds_loop_destroy(ttds_loop_t *p_this);
int ttds_loop_empty(ttds_loop_t *p_this);
int ttds_loop_poll(ttds_loop_t *p_this);
void ttds_loop_add(ttds_loop_t *p_this, ttds_thread_t *p_thread);
void ttds_loop_timer_start(ttds_loop_t *p_this, ttds_timer_t *p_timer, int ms);
void ttds_loop_timer_remove(ttds_loop_t *p_this, ttds_timer_t *p_timer);
void ttds_loop_remove(ttds_loop_t *p_this, ttds_thread_t *p_thread);
void ttds_loop_destroy(ttds_loop_t *p_this);
int ttds_loop_next_tick(ttds_loop_t *p_this);


#ifdef __cplusplus
MYPTM_CPLUSPLUS_END
#endif

#endif
